use crate::gen_title;

pub fn ch2_11_1() {
    gen_title("ch2_11_1", 18);

    #[derive(Debug)]
    enum PokerSuit {
        Clubs,
        Spades,
        Diamonds,
        Hearts,
    }

    let heart = PokerSuit::Hearts;
    let diamond = PokerSuit::Diamonds;

    print_suite(heart);
    print_suite(diamond);

    fn print_suite(card: PokerSuit) {
        println!("card: {:?}", card);
    }
}

pub fn ch2_11_2() {
    gen_title("ch2_11_2", 18);

    #[derive(Debug)]
    enum PokerSuit {
        Clubs,
        Spades,
        Diamonds,
        Hearts,
    }

    #[derive(Debug)]
    struct PokerCard {
        suit: PokerSuit,
        value: u8,
    }

    let c1 = PokerCard {
        suit: PokerSuit::Clubs,
        value: 1,
    };

    let c2 = PokerCard {
        suit: PokerSuit::Diamonds,
        value: 12,
    };

    println!("c1: {:?}", c1);
    println!("c2: {:?}", c2);
}

pub fn ch2_11_3() {
    gen_title("ch2_11_3", 18);

    #[derive(Debug)]
    enum PokerCard {
        Clubs(u8),
        Spades(u8),
        Diamonds(u8),
        Hearts(u8),
    }

    let c1 = PokerCard::Spades(5);
    let c2 = PokerCard::Diamonds(13);

    println!("c1: {:?}", c1);
    println!("c2: {:?}", c2);
}

pub fn ch2_11_4() {
    gen_title("ch2_11_4", 18);

    #[derive(Debug)]
    enum PokerCard {
        Clubs(u8),
        Spades(u8),
        Diamonds(char),
        Hearts(char),
    }

    let c1 = PokerCard::Spades(5);
    let c2 = PokerCard::Diamonds('A');

    println!("c1: {:?}", c1);
    println!("c2: {:?}", c2);
}

pub fn ch2_11_5() {
    gen_title("ch2_11_5", 18);

    #[derive(Debug)]
    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }

    let m1 = Message::Quit;
    let m2 = Message::Move { x: 1, y: 1 };
    let m3 = Message::ChangeColor(255, 255, 0);

    println!("m1: {:?}", m1);
    println!("m2: {:?}", m2);
    println!("m3: {:?}", m3);
}

pub fn ch2_11_6() {
    gen_title("ch2_11_6", 18);

    let some_number = Some(5);
    let some_string = Some("a string");
    let absent_number: Option<i32> = None;

    println!("some_number: {:?}", some_number);
    println!("some_string: {:?}", some_string);
    println!("absent_number: {:?}", absent_number);
}

pub fn ch2_11_7() {
    gen_title("ch2_11_7", 18);

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);

    println!("six: {:?}", six);
    println!("none: {:?}", none);

    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None,
            Some(i) => Some(i + 1),
        }
    }
}

pub fn ch2_11_pra_1() {
    gen_title("ch2_11_pra_1", 18);

    #[derive(Debug)]
    enum Number {
        Zero,
        One,
        Two,
    }

    #[derive(Debug)]
    enum Number1 {
        Zero = 0,
        One,
        Two,
    }

    assert_eq!(Number::One as i32, Number1::One as i32);
    assert_eq!(0, Number1::Zero as i32);

    println!("Number::Zero: {:?}", Number::Zero);
    println!("Number::One: {:?}", Number::One as i32)
}

pub fn ch2_11_pra_2() {
    gen_title("ch2_11_pra_2", 18);

    #[derive(Debug)]
    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }

    let msg1 = Message::Move { x: 1, y: 2 };
    let msg2 = Message::Write("hello".to_string());

    println!("msg1: {:?}", msg1);
    println!("msg2: {:?}", msg2);
}

pub fn ch2_11_pra_3() {
    gen_title("ch2_11_pra_3", 18);

    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }

    let msg = Message::Move { x: 1, y: 1 };

    if let Message::Move { x: a, y: b } = msg {
        assert_eq!(a, b);
        println!("a: {}, b: {}", a, b);
    } else {
        panic!("不要让这行代码运行");
    }
}

pub fn ch2_11_pra_4() {
    #[derive(Debug)]
    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }

    let msgs: [Message; 3] = [
        Message::Quit,
        Message::Move { x: 1, y: 3 },
        Message::ChangeColor(255, 255, 0),
    ];

    for msg in msgs {
        show_message(msg)
    }

    fn show_message(msg: Message) {
        println!("msg: {:?}", msg);
    }
}

pub fn ch2_11_pra_5() {
    gen_title("ch2_11_pra_5", 18);

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);

    println!("none: {:?}", none);

    if let Some(n) = six {
        println!("six: {}", n);
    }

    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None,
            Some(i) => Some(i + 1),
        }
    }
}

pub fn ch2_11_pra_6() {
    gen_title("ch2_11_pra_6", 18);

    enum List {
        Cons(u32, Box<List>),
        Nil,
    }

    impl List {
        fn new() -> List {
            List::Nil
        }

        fn prepend(self, elem: u32) -> List {
            List::Cons(elem, Box::new(self))
        }

        fn len(&self) -> u32 {
            match *self {
                List::Cons(_, ref tail) => 1 + tail.len(),
                List::Nil => 0,
            }
        }

        fn stringify(&self) -> String {
            match *self {
                List::Cons(head, ref tail) => {
                    format!("{}, {}", head, tail.stringify())
                }
                List::Nil => {
                    format!("Nil")
                }
            }
        }
    }

    let mut list = List::new();

    list = list.prepend(1);
    list = list.prepend(2);
    list = list.prepend(3);

    println!("链表的长度是: {}", list.len());
    println!("链表的结构是: {}", list.stringify());
}
